package org.zuel.boot.demo.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zuel.boot.demo.Dao.DemoUserMapper;
import org.zuel.boot.demo.component.LoginToken;
import org.zuel.boot.demo.constant.LoginType;
import org.zuel.boot.demo.constant.UserConstant;
import org.zuel.boot.demo.exception.BizException;
import org.zuel.boot.demo.model.DemoUser;
import org.zuel.boot.demo.model.DemoUserExample;
import org.zuel.boot.demo.service.IUserService;
import org.zuel.boot.demo.util.ArgumentUtil;
import org.zuel.boot.demo.util.PasswordUtil;
import org.zuel.boot.demo.util.ResponseUtil;

import java.time.LocalDateTime;
import java.util.List;


@Service
public class UserService implements IUserService {
    private final DemoUserMapper userMapper;

    @Autowired
    public UserService(DemoUserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)//回滚
    public Object regist(DemoUser model) throws BizException {
        // 参数校验
        if (model == null || !ArgumentUtil.notEmpty(model.getUsername(),
                model.getNickname(), model.getPassword())) {
            return ResponseUtil.badArgument();
        }//一个为空就报错
        // 查看用户名是否存在
        DemoUserExample example = new DemoUserExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andUsernameEqualTo(model.getUsername());
        List<DemoUser> list = userMapper.selectByExample(example);
        if (!list.isEmpty()) {
            throw new BizException(UserConstant.USERNAME_EXIST_CODE,
                    UserConstant.USERNAME_EXIST_ERROR);//注册不能让用户名存在
        }
        // 加密密码并写入新用户
        model.setPassword(PasswordUtil.encode(model.getPassword()));
        model.setAddTime(LocalDateTime.now());
        userMapper.insertSelective(model);
        model = userMapper.selectByPrimaryKey(model.getId());
        // 抹去密码, 通常不会需要展示密码
        //还真周到，我是说我输进去的好像不是乱码
        model.setPassword(null);
        return ResponseUtil.ok(model);
    }

    @Override
    public Object login(DemoUser user) throws BizException {
        // 参数校验
        if (user == null || !ArgumentUtil.notEmpty(user.getUsername(),
                user.getPassword())) {
            return ResponseUtil.badArgument();
        }
        // 密码校验
        DemoUserExample example = new DemoUserExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andUsernameEqualTo(user.getUsername());
        DemoUser model = userMapper.selectOneByExample(example);
        if (model == null) {
            throw new BizException(UserConstant.USERNAME_NOT_EXIST_CODE,
                    UserConstant.USERNAME_NOT_EXIST_ERROR);
        }
        if (!PasswordUtil.matchPwd(user.getPassword(), model.getPassword())) {
            throw new BizException(UserConstant.USER_INVALID_CODE,
                    UserConstant.USER_INVALID_ERROR);
        }
        model.setPassword(null);
        return ResponseUtil.ok(model);
    }

    @Override
    public Object list(String username, String nickname, Integer sex, String con,
                       Integer page, Integer limit, String sort, String order) {
        // limit参数有效, 则开启分页
        if (limit != -1) {
            PageHelper.startPage(page, limit);
        }
        List<DemoUser> models = userMapper
                .selectByExample(resolveCondition(username, nickname, sex, con, sort, order));
        // 统计查询结果总量
        long total = PageInfo.of(models).getTotal();
        // 抹去密码
        models.forEach(model -> model.setPassword(null));
        return ResponseUtil.ok(total, models);
    }

    private DemoUserExample resolveCondition(String username, String nickname, Integer sex,
                                             String con, String sort, String order) {
        DemoUserExample example = new DemoUserExample();
        DemoUserExample.Criteria criteria = example.createCriteria();
        // 有效数据
        criteria.andDeletedEqualTo(false);
        // 常规条件
        if (!StringUtils.isEmpty(username)) {
            criteria.andUsernameLike("%" + username + "%");
        }
        if (!StringUtils.isEmpty(nickname)) {
            criteria.andNicknameLike("%" + nickname + "%");
        }
        if (sex != null) {
            criteria.andSexEqualTo(sex);
        }
        // 通用条件
        if (!StringUtils.isEmpty(con)) {
            String strCon = "( upper(username) like upper('%" +
                    con.trim() + "%') " + "or upper(nickname) like upper('%" +
                    con.trim() + "%')) ";
            criteria.addCriterion(strCon);
        }
        // 排序规则
        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }
        return example;
    }

    @Override
    public Object read(Integer id) {
        if (id == null) {
            return ResponseUtil.primaryKeyInvalid();
        }
        DemoUser model = userMapper.selectByPrimaryKeyWithLogicalDelete(id, false);
        if (model == null) {
            return ResponseUtil.dataNotExist();
        }
        model.setPassword(null);
        return model;
    }

    @Override
    public Object login2(DemoUser param) {
        if (param == null || StringUtils.isEmpty(param.getUsername())
                || StringUtils.isEmpty(param.getPassword())) {
            return ResponseUtil.badArgument();
        }//类似于重写login方法
        return ResponseUtil.ok(login(new LoginToken(LoginType.USER_PASSWORD,//需要检查登录类型
                param.getUsername(), param.getPassword())));
    }

    private Object login(LoginToken token) {//这是所有的最终归宿
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        return subject.getSession().getId();
    }
    //你告诉你坝securityUtils这个类是什么，一引用就能用
    @Override
    public Object logout() {
        Subject curUser = SecurityUtils.getSubject();
        curUser.logout();
        return ResponseUtil.ok();
    }

    @Override
    public Object showMe() {
        Subject subject = SecurityUtils.getSubject();
        DemoUser user = (DemoUser) subject.getPrincipal();
        user.setPassword(null);
        return ResponseUtil.ok(user);
    }
}
